일급 컬렉션
일급 컬렉션 (First-Class Collection)
컬렉션을 단 하나의 멤버 변수로만 가지는 클래스로 감싸는 패턴
개념
// Before — 컬렉션이 외부에 노출
List<Car> cars = new ArrayList<>();
// After — 일급 컬렉션으로 감싸기
public class Cars {
private final List<Car> cars; // 컬렉션 하나만 멤버 변수로 가짐
public Cars(List<Car> cars) {
validate(cars);
this.cars = new ArrayList<>(cars);
}
}
이점
| 이점 | 설명 |
|---|---|
| 비즈니스 규칙 집중 | 컬렉션 관련 검증·조작 로직을 한 곳에 모음 |
| 캡슐화 | 외부에서 컬렉션을 직접 수정 불가 |
| 상태 보호 | Collections.unmodifiableList()로 노출 시 불변 보장 |
| 책임 명확화 | Cars가 자동차 목록에 대한 책임을 전담 |
실전 예시 — 자동차 경주
public class Cars {
private final List<Car> cars;
public Cars(String[] names) {
this.cars = Arrays.stream(names)
.maptrim
.mapnew
.collect(Collectors.toList());
validate();
}
private void validate() {
if (cars.isEmpty()) throw new CarRacingException(ErrorCode.EMPTY_CARS);
// 중복 검증 등
}
public List<Car> getCars() {
return Collections.unmodifiableList(cars); // 외부 수정 차단
}
public List<Car> getWinners() {
int maxPosition = cars.stream()
.mapToIntgetPosition
.max()
.orElse(0);
return cars.stream()
.filter(car -> car.getPosition() == maxPosition)
.collect(Collectors.toList());
}
}
검증 책임 위치
일급 컬렉션이 자신의 유효성을 직접 검증하는 것이 원칙.
입력값 파싱은 InputView, 도메인 규칙 검증은 도메인 객체 본인.
InputView → 입력 받기 (파싱)
Cars 생성자 → 도메인 규칙 검증 (중복, 최소 개수 등)
Car 생성자 → 단일 객체 규칙 검증 (이름 길이 등)